home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / daemons / nfs / nfs-serv.2be / nfs-serv / nfs-server-2.2beta16 / auth.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-28  |  17.9 KB  |  795 lines

  1. /*
  2.  * This module contains all generic functions used by the authentication
  3.  * mechanism.
  4.  *
  5.  * Copyright (C) 1995 Olaf Kirch  <okir@monad.swb.de>
  6.  *
  7.  * This software maybe be used for any purpose provided
  8.  * the above copyright notice is retained.  It is supplied
  9.  * as is, with no warranty expressed or implied.
  10.  */
  11.  
  12. #include "nfsd.h"
  13.  
  14. #define AUTH_DEBUG
  15.  
  16. static _PRO( int hostmatch, (const char *, const char *)        );
  17. static _PRO( void auth_check_wildcards, (nfs_client *cp)        );
  18. static _PRO( void auth_add_mountlist, (nfs_client *, nfs_mount *)    );
  19. static _PRO( void auth_create_hashent, (nfs_client *, struct in_addr *)    );
  20. static _PRO( void auth_free_list, (nfs_client **)            );
  21. static _PRO( void auth_warn_anon, (void)                );
  22.  
  23. /* It appears to be an old and long-standing tradition on Unices not
  24.  * to declare the netgroup functions in any header file
  25.  */
  26. extern _PRO( int setnetgrent, (char *netgroup)                );
  27. extern _PRO( int getnetgrent, (char **host, char **user, char **domain)    );
  28. extern _PRO( int endnetgrent, (void)                    );
  29.  
  30.  
  31. #define IPHASH(a)    (((a)^((a)>>8)^((a)>>16)^((a)>>24)) & (IPHASHMAX-1))
  32. #define IPHASHMAX    32
  33.  
  34. typedef struct nfs_hash_ent {
  35.     struct nfs_hash_ent    *next;
  36.     struct in_addr        addr;
  37.     nfs_client        *client;
  38. } nfs_hash_ent;
  39.  
  40. static nfs_hash_ent        *hashtable[IPHASHMAX];
  41. static nfs_client        *known_clients = NULL;
  42. static nfs_client        *unknown_clients = NULL;
  43. static nfs_client        *wildcard_clients = NULL;
  44. static nfs_client        *netgroup_clients = NULL;
  45. static nfs_client        *netmask_clients = NULL;
  46. static nfs_client        *anonymous_client = NULL;
  47. static nfs_client        *default_client = NULL;
  48. static int            initialized = 0;
  49.  
  50. static nfs_options        default_options = {
  51.                     identity,    /* uid mapping */
  52.                     1,        /* root squash */
  53.                     0,        /* all squash */
  54.                     1,        /* secure port */
  55.                     0,        /* read-only */
  56.                     0,        /* relative links */
  57.                     0,        /* noaccess */
  58.                     (uid_t)-2,    /* default uid */
  59.                     (gid_t)-2,    /* default gid */
  60.                 };
  61.  
  62. /*
  63.  * Get a client entry for a specific name or pattern.
  64.  * If necessary, this function performs a hostname lookup to
  65.  * obtain the host's FQDN. This is for the benefit of those who
  66.  * use aliases in /etc/exports, or mix qualified and unqualified
  67.  * hostnames.
  68.  *
  69.  * FIXME: Make this function create the nfs_client entry if none
  70.  * is found. Currently, this function is called only from auth_init
  71.  * anyway, which creates the client entry if this function returns
  72.  * NULL.
  73.  */
  74. nfs_client *
  75. auth_get_client(hname)
  76. char *hname;
  77. {
  78.     struct hostent    *hp;
  79.     nfs_client    *cp;
  80.  
  81.     if (hname == NULL || *hname == '\0') {
  82.         auth_warn_anon();
  83.         return anonymous_client;
  84.     }
  85.  
  86.     if (strchr(hname, '*') != NULL || strchr(hname, '?') != NULL) {
  87.         for (cp = wildcard_clients; cp != NULL; cp = cp->next) {
  88.             if (!strcmp(cp->clnt_name, hname))
  89.                 return cp;
  90.         }
  91.         return NULL;
  92.     }
  93.  
  94.     for (cp = unknown_clients; cp != NULL; cp = cp->next) {
  95.         if (!strcmp(cp->clnt_name, hname))
  96.             return cp;
  97.     }
  98.  
  99.     for (cp = known_clients; cp != NULL; cp = cp->next) {
  100.         if (!strcmp(cp->clnt_name, hname))
  101.             return cp;
  102.     }
  103.  
  104.     if ((hp = gethostbyname(hname)) != NULL) {
  105.         for (cp = known_clients; cp != NULL; cp = cp->next) {
  106.             if (!strcmp(cp->clnt_name, hp->h_name))
  107.                 return cp;
  108.         }
  109.     }
  110.  
  111.     return NULL;
  112. }
  113.  
  114. /*
  115.  * Given a client and a pathname, try to find the proper mount point.
  116.  * This code relies on the mount list being sorted from largest to
  117.  * smallest w.r.t strcmp.
  118.  */
  119. nfs_mount *
  120. auth_match_mount(cp, path)
  121. nfs_client *cp;
  122. char *path;
  123. {
  124.     nfs_mount    *mp;
  125.     char        c;
  126.  
  127.     if (path == NULL)
  128.         return NULL;
  129.  
  130.     for (mp = cp->m; mp != NULL; mp = mp->next) {
  131.         if (!strncmp(mp->path, path, mp->length) &&
  132.             ((c = path[mp->length]) == '/' || c == '\0')) {
  133.             return mp;
  134.         }
  135.     }
  136.     return NULL;
  137. }
  138.  
  139. /*
  140.  * Find a known client given its IP address.
  141.  * The matching hash entry is moved to the list head. This may be useful
  142.  * for sites with large exports list (e.g. due to huge netgroups).
  143.  */
  144. nfs_client *
  145. auth_known_clientbyaddr(addr)
  146. struct in_addr    addr;
  147. {
  148.     nfs_hash_ent    **htp, *hep, *prv;
  149.  
  150.     htp = hashtable + IPHASH(addr.s_addr);
  151.     hep = *htp;
  152.     for (prv = NULL; hep != NULL; prv = hep, hep = hep->next) {
  153.         if (hep->addr.s_addr == addr.s_addr) {
  154.             if (prv != NULL) {
  155.                 prv->next = hep->next;
  156.                 hep->next = *htp;
  157.                 *htp = hep;
  158.             }
  159.             hep->client->clnt_addr = addr;
  160.             return hep->client;
  161.         }
  162.     }
  163.     return NULL;
  164. }
  165.  
  166. /*
  167.  * Find a known client given its FQDN.
  168.  */
  169. nfs_client *
  170. auth_known_clientbyname(hname)
  171. char *hname;
  172. {
  173.     nfs_client    *cp;
  174.  
  175.     if (hname == NULL)
  176.         return NULL;
  177.  
  178.     for (cp = known_clients; cp != NULL; cp = cp->next) {
  179.         if (!strcmp(cp->clnt_name, hname))
  180.             return cp;
  181.     }
  182.     return NULL;
  183. }
  184.  
  185. /*
  186.  * Find an unknown client given its IP address. This functions checks
  187.  * previously unresolved hostnames, wildcard hostnames, the anon client,
  188.  * and the default client.
  189.  */
  190. nfs_client *
  191. auth_unknown_clientbyaddr(addr)
  192. struct in_addr addr;
  193. {
  194.     struct hostent    *hp;
  195.     nfs_client    *cp, *ncp;
  196.     char        *hname;
  197.  
  198.     dprintf(D_AUTH, "check unknown clnt addr %s\n", inet_ntoa(addr));
  199.     hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
  200.  
  201.     for (cp = netmask_clients; cp != NULL; cp = cp->next) {
  202.         if (!((addr.s_addr^cp->clnt_addr.s_addr)&cp->clnt_mask.s_addr))
  203.             break;
  204.     }
  205.     if (cp != NULL) {
  206.         dprintf(D_AUTH, "client %s matched %s/%s\n",
  207.             hp? hp->h_name : inet_ntoa(addr), cp->clnt_name);
  208.         ncp = auth_create_client(hp? hp->h_name : inet_ntoa(addr), hp);
  209.         auth_add_mountlist(ncp, cp->m);
  210.         auth_check_wildcards(ncp);
  211.         return ncp;
  212.     }
  213.  
  214.     if (hp != NULL) {
  215.         nfs_client **cpp;
  216.         char    **ap;
  217.  
  218.         /* So, this is ugly, but we don't do it that often. And it's
  219.          * better than fixed size strings
  220.          */
  221.         hname = malloc(strlen(hp->h_name) + 1);
  222.         strcpy (hname, hp->h_name);
  223.         hp = gethostbyname(hname);
  224.         free (hname);
  225.         hname = (char *) hp->h_name;
  226.  
  227.         if (hp == NULL) {
  228.             if (trace_spoof)
  229.                 dprintf(L_ERROR,
  230.                 "couldn't verify address of host %s\n",
  231.                 hp->h_name);
  232.             goto anonymous;
  233.         }
  234.         for (ap = hp->h_addr_list; *ap != NULL; ap++) {
  235.             if (!memcmp(*ap, (char *)&addr, hp->h_length))
  236.                 break;
  237.         }
  238.  
  239.         /* Okay, so this is a spoof attempt. */
  240.         if (*ap == NULL) {
  241.             dprintf(L_ERROR,
  242.                 "spoof attempt by %s: pretends to be %s!\n",
  243.                 inet_ntoa(addr), hp->h_name);
  244.             goto anonymous;
  245.         }
  246.  
  247.         dprintf(D_AUTH, "\tclient name is %s\n", hp->h_name);
  248.  
  249.         /* First, check for clients that couldn't be resolved during
  250.          * initialization */
  251.         for (cpp = &unknown_clients; *cpp!=NULL; cpp = &(*cpp)->next) {
  252.             if (!strcmp((*cpp)->clnt_name, hp->h_name)) {
  253.                 nfs_client *cp;
  254.  
  255.                 dprintf(D_AUTH,
  256.                     "Found previously unknown host %s\n",
  257.                     hp->h_name);
  258.                 cp = *cpp;
  259.                 cp->clnt_addr = addr;
  260.  
  261.                 /* remove client from list of unknown and
  262.                  * add it to list of known hosts.
  263.                  */
  264.                 (*cpp) = (*cpp)->next;
  265.                 cp->next = known_clients;
  266.                 known_clients = cp;
  267.  
  268.                 /* Add host to hashtable */
  269.                 for (ap = hp->h_addr_list; *ap != NULL; ap++) {
  270.                     auth_create_hashent(cp, 
  271.                             (struct in_addr *)*ap);
  272.                 }
  273.  
  274.                 return cp;
  275.             }
  276.         }
  277.  
  278.         /* Okay, now check for wildcard names. NB the wildcard
  279.          * patterns are sorted from most to least specific.
  280.          *
  281.          * The pattern matching should also be applied to
  282.          * all names in h_aliases.
  283.          */
  284.         for (cpp = &wildcard_clients; *cpp!=NULL; cpp = &(*cpp)->next) {
  285.             if (hostmatch(hp->h_name, (*cpp)->clnt_name)) {
  286.                 nfs_client *cp;
  287.  
  288.                 dprintf(D_AUTH,
  289.                     "client %s matched pattern %s\n",
  290.                     hp->h_name, (*cpp)->clnt_name);
  291.                 cp = auth_create_client(hp->h_name, hp);
  292.                 auth_check_wildcards(cp);
  293.                 return cp;
  294.             }
  295.         }
  296.     } else {
  297.         hname = inet_ntoa(addr);
  298.     }
  299.  
  300. anonymous:
  301.     if (anonymous_client != NULL) {
  302.         dprintf(D_AUTH, "Anonymous request from %s.\n", hname);
  303.         cp = anonymous_client;
  304.     } else
  305.         cp = default_client;
  306.  
  307.     if (cp) {
  308.         ncp = auth_create_client(hname, hp);
  309.         auth_add_mountlist(ncp, cp->m);
  310.         return ncp;
  311.     }
  312.     return NULL;
  313. }
  314.  
  315. /*
  316.  * Create a client struct for the given hostname. The hp parameter
  317.  * optionally contains hostent information obtained from a previous
  318.  * gethostbyname.
  319.  */
  320. nfs_client *
  321. auth_create_client(hname, hp)
  322. const char *hname;
  323. struct hostent *hp;
  324. {
  325.     nfs_client    *cp, **cpp;
  326.     int        wildcards, netgroup, netmask, namelen;
  327.  
  328.     cp = (nfs_client *) xmalloc(sizeof(nfs_client));
  329.  
  330.     cp->clnt_addr.s_addr = INADDR_ANY;
  331.     cp->flags = 0;
  332.     cp->m = NULL;
  333.     cp->umap = NULL;
  334.  
  335.     if (hname == NULL) {
  336.         if (anonymous_client != NULL) {
  337.             free (cp);
  338.             cp = anonymous_client;
  339.         } else {
  340.             anonymous_client = cp;
  341.         }
  342.         cp->clnt_name = NULL;
  343.         cp->next = NULL;
  344.         cp->flags = AUTH_CLNT_ANONYMOUS;
  345.         return cp;
  346.     }
  347.  
  348.     wildcards = (strchr(hname, '*') != NULL || strchr(hname, '?') != NULL);
  349.     netgroup = (hname[0] == '@');
  350.     netmask = (strchr(hname, '/') != NULL);
  351.  
  352.     if (!wildcards && !netgroup && !netmask && hp == NULL) {
  353.         hp = gethostbyname(hname);
  354.     }
  355.     if (hp != NULL) {
  356.         if (hp->h_addrtype != AF_INET) {
  357.             dprintf(L_WARNING,
  358.                 "%s has address type %d != AF_INET.\n",
  359.                 hp->h_name, hp->h_addrtype);
  360.             free (cp);
  361.             return NULL;
  362.         }
  363.         hname = hp->h_name;    /* use FQDN */
  364.     }
  365.  
  366.     cp->clnt_name = xstrdup(hname);
  367.  
  368.     if (wildcards) {
  369.         /* We have a wildcard name. Wildcard names are sorted
  370.          * in order of descending pattern length. This way,
  371.          * pattern *.pal.xgw.fi is matched before *.xgw.fi.
  372.          */
  373.         cp->flags = AUTH_CLNT_WILDCARD;
  374.         cpp = &wildcard_clients;
  375.         namelen = strlen(hname);
  376.         while (*cpp != NULL && namelen <= strlen((*cpp)->clnt_name)) {
  377.             cpp = &((*cpp)->next);
  378.         }
  379.     } else if (netgroup) {
  380.         /* Netgroup name. These are added to a separate list. This
  381.          * list won't be consulted, but we have to keep the struct
  382.          * around because of the way exports parsing is done.
  383.          */
  384.         cp->flags = AUTH_CLNT_NETGROUP;
  385.         cpp = &netgroup_clients;
  386.     } else if (netmask) {
  387.         /* Address/mask pair. */
  388.         char    *slashp = strchr(hname, '/');
  389.         cp->flags = AUTH_CLNT_NETMASK;
  390.         cpp = &netmask_clients;
  391.         *slashp = '\0';
  392.         cp->clnt_mask.s_addr = inet_addr(slashp+1);
  393.         cp->clnt_addr.s_addr = inet_addr(hname);
  394.         if (cp->clnt_addr.s_addr == -1 || cp->clnt_mask.s_addr == -1) {
  395.             *slashp = '/';
  396.             dprintf(L_ERROR, "bad addr/mask value: %s", hname);
  397.         }
  398.     } else if (hp == NULL) {
  399.         cpp = &unknown_clients;
  400.     } else {
  401.         char    **ap;
  402.  
  403.         cpp = &known_clients;
  404.         for (ap = hp->h_addr_list; *ap != NULL; ap++) {
  405.             auth_create_hashent(cp, (struct in_addr *)*ap);
  406.         }
  407.     }
  408.     cp->next = *cpp;
  409.     *cpp = cp;
  410.  
  411.     return cp;
  412. }
  413.  
  414. /*
  415.  * Create the default client.
  416.  */
  417. nfs_client *
  418. auth_create_default_client()
  419. {
  420.     nfs_client    *cp;
  421.  
  422.     if (default_client == NULL) {
  423.         cp = (nfs_client *) xmalloc(sizeof(nfs_client));
  424.         cp->clnt_name = NULL;
  425.         cp->next = NULL;
  426.         cp->flags = AUTH_CLNT_DEFAULT;
  427.         cp->m = NULL;
  428.         default_client = cp;
  429.     }
  430.     auth_warn_anon();
  431.     return default_client;
  432. }
  433.  
  434. static void
  435. auth_warn_anon()
  436. {
  437.     static int    warned = 0;
  438.     struct hostent    *hp;
  439.     char        name[257];
  440.     char        **ap;
  441.  
  442.     if (warned)
  443.         return;
  444.     warned = 1;
  445.  
  446.     if (gethostname(name, sizeof(name)) < 0) {
  447.         dprintf(L_ERROR, "can't get local hostname");
  448.         return;
  449.     }
  450.     if ((hp = gethostbyname(name)) == NULL) {
  451.         dprintf(L_ERROR, "can't get my own address");
  452.         return;
  453.     }
  454.     if (hp->h_addrtype != AF_INET) {
  455.         dprintf(L_ERROR, "local host address is not AF_INET?!");
  456.         return;
  457.     }
  458.     for (ap = hp->h_addr_list; *ap; ap++) {
  459.         struct in_addr    addr;
  460.         unsigned long    net3, net2;
  461.  
  462.         addr = *(struct in_addr *) *ap;
  463.         net3 = ntohl(addr.s_addr) & 0xff000000;
  464.         net2 = ntohl(addr.s_addr) & 0x00ff0000;
  465.         if (net3 == 0x0A000000 ||
  466.            (net3 == 0xAC000000 && 0x100000 <= net2 && net2 < 0x200000)||
  467.            (net3 == 0XC0000000 && 0xA80000 == net2))
  468.             continue;
  469.         dprintf(L_WARNING, "exports file has anon entries, but host\n");
  470.         dprintf(L_WARNING, "has non-private IP address %s!\n",
  471.                     inet_ntoa(addr));
  472.     }
  473. }
  474.  
  475. /*
  476.  * Create an entry in the hashtable of known clients.
  477.  */
  478. void
  479. auth_create_hashent(cp, ap)
  480. nfs_client    *cp;
  481. struct in_addr    *ap;
  482. {
  483.     nfs_hash_ent    *hep;
  484.     int        hash;
  485.  
  486.     hash = IPHASH(ap->s_addr);
  487.  
  488.     hep = (nfs_hash_ent *) xmalloc(sizeof(*hep));
  489.     hep->client = cp;
  490.     hep->addr = *ap;
  491.     hep->next = hashtable[hash];
  492.     hashtable[hash] = hep;
  493. }
  494.  
  495. /*
  496.  * After reading the entire exports file, this routine checks if any
  497.  * of the known clients match any of the patterns in wildcard_clients.
  498.  * If one does, the wildcard's mount points are added to its list of
  499.  * mount points.
  500.  */
  501. void
  502. auth_check_all_wildcards(void)
  503. {
  504.     nfs_client    *cp;
  505.  
  506.     for (cp = wildcard_clients; cp != NULL; cp = cp->next) {
  507.         nfs_mount    *mp;
  508.  
  509.         dprintf(D_AUTH, "wildcard clnt %s:\n", cp->clnt_name);
  510.         for (mp = cp->m; mp != NULL; mp = mp->next)
  511.             dprintf(D_AUTH, "\texport %s:\n", mp->path);
  512.     }
  513.  
  514.     for (cp = known_clients; cp != NULL; cp = cp->next) {
  515.         auth_check_wildcards(cp);
  516.     }
  517.     for (cp = unknown_clients; cp != NULL; cp = cp->next) {
  518.         auth_check_wildcards(cp);
  519.     }
  520. }
  521.  
  522. static void
  523. auth_check_wildcards(cp)
  524. nfs_client *cp;
  525. {
  526.     nfs_client    *wcp;
  527.     nfs_mount    *mp;
  528.  
  529.     for (wcp = wildcard_clients; wcp != NULL; wcp = wcp->next) {
  530.         if (hostmatch(cp->clnt_name, wcp->clnt_name)) {
  531.             auth_add_mountlist(cp, wcp->m);
  532.         }
  533.     }
  534.     if (anonymous_client != NULL) {
  535.         auth_add_mountlist(cp, anonymous_client->m);
  536.     }
  537.     for (mp = cp->m; mp != NULL; mp = mp->next) {
  538.         dprintf(D_AUTH, "\tclnt %s exp %s\n",
  539.             cp->clnt_name, mp->path);
  540.     }
  541. }
  542.  
  543. /*
  544.  * Check all client structs that apply to a netgroup
  545.  */
  546. void
  547. auth_check_all_netgroups(void)
  548. {
  549. #ifdef HAVE_GETNETGRENT
  550.     nfs_client    *ncp, *cp;
  551.  
  552.     for (ncp = netgroup_clients; ncp != NULL; ncp = ncp->next) {
  553.         char    *hname, *user, *domain;
  554.  
  555.         setnetgrent(ncp->clnt_name + 1);
  556.         while (getnetgrent(&hname, &user, &domain)) {
  557.             if (hname == NULL || *hname == '\0' || !strcmp(hname, "-"))
  558.                 continue;
  559.             if ((cp = auth_get_client(hname)) == NULL &&
  560.                 (cp = auth_create_client(hname, NULL)) == NULL)
  561.                 continue;
  562.             auth_add_mountlist(cp, ncp->m);
  563.         }
  564.         endnetgrent();
  565.     }
  566. #endif
  567. }
  568.  
  569. /*
  570.  * Check all client structs that match an addr/mask pair
  571.  */
  572. void
  573. auth_check_all_netmasks(void)
  574. {
  575.     nfs_client    *ncp, *cp;
  576.     nfs_hash_ent    *hp;
  577.     int        i, match;
  578.  
  579.     for (ncp = netmask_clients; ncp != NULL; ncp = ncp->next) {
  580.         for (i = 0; i < IPHASHMAX; i++) {
  581.             for (hp = hashtable[i]; hp != NULL; hp = hp->next) {
  582.                 match = ((hp->addr.s_addr 
  583.                         ^ ncp->clnt_addr.s_addr)
  584.                             & ncp->clnt_mask.s_addr) == 0;
  585.                 if (match) {
  586.                     cp = hp->client;
  587.                     auth_add_mountlist(cp, ncp->m);
  588.                 }
  589.             }
  590.         }
  591.     }
  592. }
  593.  
  594. /*
  595.  * Add a mount point to a client. Mount points are sorted from most
  596.  * specific to least specific.
  597.  */
  598. nfs_mount *
  599. auth_add_mount(cp, path)
  600. nfs_client *cp;
  601. char *path;
  602. {
  603.     nfs_mount    *mp, **mpp;
  604.     int        len;
  605.  
  606.     len = strlen(path);
  607.  
  608.     mp = (nfs_mount*) xmalloc(sizeof(nfs_mount));
  609.     memcpy (&mp->o, &default_options, sizeof(nfs_options));
  610.     mp->client = cp;
  611.  
  612.     mp->path = xstrdup(path);
  613.     while (len && mp->path[len-1] == '/')
  614.         mp->path[--len] = '\0';
  615.     mp->length = len;
  616.  
  617.     /* insert mount point into list of mounts. Insert more specific
  618.      * path before less specific path. For equal mount points, the
  619.      * first one entered wins so that exports entries like
  620.      *
  621.      * /foo/bar    (ro) host1(rw,no_root_squash)
  622.      *
  623.      * do the intuitive thing.
  624.      */
  625.     for (mpp = &(cp->m); *mpp != NULL; mpp = &(*mpp)->next) {
  626.         if (strcmp((*mpp)->path, path) < 0)
  627.             break;
  628.     }
  629.  
  630.     mp->next = *mpp;
  631.     *mpp = mp;
  632.  
  633.     return mp;
  634. }
  635.  
  636. /*
  637.  * Add a list of mount points to an existing client. This code looks
  638.  * somewhat sub-optimal, but we have to make sure the overall order
  639.  * of mount points is preserved (i.e. most specific to least specific).
  640.  * Few Linux machines will have more than a dozen or so paths in their
  641.  * exports file anyway.
  642.  */
  643. static void
  644. auth_add_mountlist(cp, mp)
  645. nfs_client *cp;
  646. nfs_mount *mp;
  647. {
  648.     nfs_mount    *nmp;
  649.  
  650.     while (mp != NULL) {
  651.     nmp = auth_add_mount(cp, mp->path);
  652.     memcpy (&(nmp->o), &(mp->o), sizeof(nfs_options));
  653.  
  654.     mp = mp->next;
  655.     }
  656. }
  657.  
  658. /*
  659.  * Match a hostname against a pattern.
  660.  */
  661. static int
  662. hostmatch(hname, pattern)
  663. const char *hname;
  664. const char *pattern;
  665. {
  666.     int seen_dot = 0;
  667.  
  668.     dprintf(D_AUTH, "host matching %s to %s\n", hname, pattern);
  669.  
  670.     for (;;) {
  671.         if (*hname == '\0' || *pattern == '\0')
  672.             return (*hname == *pattern);
  673.         switch (*pattern) {
  674.         case '*':
  675.             while (*hname != '.' && *hname != '\0')
  676.                 hname++;
  677.             seen_dot = 1;
  678.             pattern++;
  679.             break;
  680.         case '?':
  681.             if (*hname == '.')
  682.                 return (0);
  683.             hname++;
  684.             pattern++;
  685.             break;
  686.         default:
  687.             if (seen_dot) {
  688.                 if (tolower(*hname) != tolower(*pattern))
  689.                     return (0);
  690.             }
  691.             else if (*hname != *pattern)
  692.                 return (0);
  693.             if (*pattern == '.')
  694.                 seen_dot = 1;
  695.             hname++;
  696.             pattern++;
  697.             break;
  698.         }
  699.     }
  700. }
  701.  
  702. /*
  703.  * Initialize hash table. If the auth module has already been initialized, 
  704.  * free all list entries first.
  705.  */
  706. void
  707. auth_init_lists()
  708. {
  709.     struct passwd    *pw;
  710.     int        i;
  711.     uid_t        anon_uid;
  712.     gid_t        anon_gid;
  713.  
  714.     if (initialized) {
  715.         nfs_hash_ent    *hep, *next;
  716.  
  717.         auth_free_list(&known_clients);
  718.         auth_free_list(&unknown_clients);
  719.         auth_free_list(&wildcard_clients);
  720.         auth_free_list(&netgroup_clients);
  721.         auth_free_list(&anonymous_client);
  722.         auth_free_list(&default_client);
  723.  
  724.         for (i = 0; i < IPHASHMAX; i++) {
  725.             for (hep = hashtable[i]; hep != NULL; hep = next) {
  726.                 next = hep->next;
  727.                 free (hep);
  728.             }
  729.             hashtable[i] = NULL;
  730.         }
  731.     } else {
  732.         for (i = 0; i < IPHASHMAX; i++) {
  733.             hashtable[i] = NULL;
  734.         }
  735.     }
  736.  
  737.     /* Get the default anon uid/gid */
  738.     if ((pw = getpwnam("nobody")) != NULL) {
  739.         anon_uid = pw->pw_uid;
  740.         anon_gid = pw->pw_gid;
  741.     } else {
  742.         anon_uid = (uid_t) -2;
  743.         anon_gid = (gid_t) -2;
  744.     }
  745.  
  746.     /* This protects us from stomping all over the place on installations
  747.      * that have given nobody a uid/gid of -1. This is quite bad for
  748.      * systems that don't have setfsuid, because seteuid(-1) is a no-op.
  749.      */
  750.     if (anon_uid == (uid_t)-1) {
  751.         dprintf(L_ERROR,
  752.             "Eek: user nobody has uid -1. Using -2 instead.\n");
  753.         anon_uid = (uid_t) -2;
  754.     }
  755.     if (anon_gid == (gid_t)-1) {
  756.         dprintf(L_ERROR,
  757.             "Eek: user nobody has gid -1. Using -2 instead.\n");
  758.         anon_gid = (gid_t) -2;
  759.     }
  760.  
  761.     default_options.nobody_uid = anon_uid;
  762.     default_options.nobody_gid = anon_gid;
  763.  
  764.     initialized = 1;
  765. }
  766.  
  767. /*
  768.  * Free all members on a list of nfs_clients.
  769.  */
  770. static void
  771. auth_free_list(cpp)
  772. nfs_client    **cpp;
  773. {
  774.     nfs_client    *cp, *nxt_clnt;
  775.     nfs_mount    *mp, *nxt_mp;
  776.  
  777.     for (cp = *cpp; cp != NULL; cp = nxt_clnt) {
  778.         nxt_clnt = cp->next;
  779.         if (cp->clnt_name != NULL) {
  780.             free (cp->clnt_name);
  781.         }
  782.         for (mp = cp->m; mp != NULL; mp = nxt_mp) {
  783.             nxt_mp = mp->next;
  784.             free (mp->path);
  785.             free (mp);
  786.         }
  787.         if (cp->umap != NULL) {
  788.             ugid_free_map(cp->umap);
  789.         }
  790.         free (cp);
  791.     }
  792.     *cpp = NULL;
  793. }
  794.  
  795.